home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / c / time / ctime.c < prev    next >
C/C++ Source or Header  |  1988-07-29  |  9KB  |  400 lines

  1. /*
  2.  * Copyright (c) 1987 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific written prior permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  *
  12.  * This code was supplied by Arthur Olson, originally, and has been
  13.  * slightly modified at the University of California.
  14.  */
  15.  
  16. #if defined(LIBC_SCCS) && !defined(lint)
  17. static char sccsid[] = "@(#)ctime.c    5.12 (Berkeley) 12/3/87";
  18. #endif /* LIBC_SCCS and not lint */
  19.  
  20. #include <stdio.h>
  21. #include <sys/param.h>
  22. #include <sys/time.h>
  23. #include <tzfile.h>
  24.  
  25. char *
  26. ctime(t)
  27. time_t *t;
  28. {
  29.     struct tm    *localtime();
  30.     char    *asctime();
  31.  
  32.     return(asctime(localtime(t)));
  33. }
  34.  
  35. /*
  36. ** A la X3J11
  37. */
  38.  
  39. char *
  40. asctime(timeptr)
  41. register struct tm *    timeptr;
  42. {
  43.     static char    wday_name[DAYS_PER_WEEK][3] = {
  44.         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  45.     };
  46.     static char    mon_name[MONS_PER_YEAR][3] = {
  47.         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  48.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  49.     };
  50.     static char    result[26];
  51.  
  52.     (void) sprintf(result, "%.3s %.3s%3d %02d:%02d:%02d %d\n",
  53.         wday_name[timeptr->tm_wday],
  54.         mon_name[timeptr->tm_mon],
  55.         timeptr->tm_mday, timeptr->tm_hour,
  56.         timeptr->tm_min, timeptr->tm_sec,
  57.         TM_YEAR_BASE + timeptr->tm_year);
  58.     return result;
  59. }
  60.  
  61. #ifndef TRUE
  62. #define TRUE        1
  63. #define FALSE        0
  64. #endif /* !TRUE */
  65.  
  66. extern char *        getenv();
  67. extern char *        strcpy();
  68. extern char *        strcat();
  69. struct tm *        offtime();
  70.  
  71. struct ttinfo {                /* time type information */
  72.     long        tt_gmtoff;    /* GMT offset in seconds */
  73.     int        tt_isdst;    /* used to set tm_isdst */
  74.     int        tt_abbrind;    /* abbreviation list index */
  75. };
  76.  
  77. struct state {
  78.     int        timecnt;
  79.     int        typecnt;
  80.     int        charcnt;
  81.     time_t        ats[TZ_MAX_TIMES];
  82.     unsigned char    types[TZ_MAX_TIMES];
  83.     struct ttinfo    ttis[TZ_MAX_TYPES];
  84.     char        chars[TZ_MAX_CHARS + 1];
  85. };
  86.  
  87. static struct state    s;
  88.  
  89. static int        tz_is_set;
  90.  
  91. char *            tzname[2] = {
  92.     "GMT",
  93.     "GMT"
  94. };
  95.  
  96. #ifdef USG_COMPAT
  97. time_t            timezone = 0;
  98. int            daylight = 0;
  99. #endif /* USG_COMPAT */
  100.  
  101. static long
  102. detzcode(codep)
  103. char *    codep;
  104. {
  105.     register long    result;
  106.     register int    i;
  107.  
  108.     result = 0;
  109.     for (i = 0; i < 4; ++i)
  110.         result = (result << 8) | (codep[i] & 0xff);
  111.     return result;
  112. }
  113.  
  114. static
  115. tzload(name)
  116. register char *    name;
  117. {
  118.     register int    i;
  119.     register int    fid;
  120.  
  121.     if (name == 0 && (name = TZDEFAULT) == 0)
  122.         return -1;
  123.     {
  124.         register char *    p;
  125.         register int    doaccess;
  126.         char        fullname[MAXPATHLEN];
  127.  
  128.         doaccess = name[0] == '/';
  129.         if (!doaccess) {
  130.             if ((p = TZDIR) == 0)
  131.                 return -1;
  132.             if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
  133.                 return -1;
  134.             (void) strcpy(fullname, p);
  135.             (void) strcat(fullname, "/");
  136.             (void) strcat(fullname, name);
  137.             /*
  138.             ** Set doaccess if '.' (as in "../") shows up in name.
  139.             */
  140.             while (*name != '\0')
  141.                 if (*name++ == '.')
  142.                     doaccess = TRUE;
  143.             name = fullname;
  144.         }
  145.         if (doaccess && access(name, 4) != 0)
  146.             return -1;
  147.         if ((fid = open(name, 0, 0)) == -1)
  148.             return -1;
  149.     }
  150.     {
  151.         register char *            p;
  152.         register struct tzhead *    tzhp;
  153.         char                buf[sizeof s];
  154.  
  155.         i = read(fid, buf, sizeof buf);
  156.         if (close(fid) != 0 || i < sizeof *tzhp)
  157.             return -1;
  158.         tzhp = (struct tzhead *) buf;
  159.         s.timecnt = (int) detzcode(tzhp->tzh_timecnt);
  160.         s.typecnt = (int) detzcode(tzhp->tzh_typecnt);
  161.         s.charcnt = (int) detzcode(tzhp->tzh_charcnt);
  162.         if (s.timecnt > TZ_MAX_TIMES ||
  163.             s.typecnt == 0 ||
  164.             s.typecnt > TZ_MAX_TYPES ||
  165.             s.charcnt > TZ_MAX_CHARS)
  166.                 return -1;
  167.         if (i < sizeof *tzhp +
  168.             s.timecnt * (4 + sizeof (char)) +
  169.             s.typecnt * (4 + 2 * sizeof (char)) +
  170.             s.charcnt * sizeof (char))
  171.                 return -1;
  172.         p = buf + sizeof *tzhp;
  173.         for (i = 0; i < s.timecnt; ++i) {
  174.             s.ats[i] = detzcode(p);
  175.             p += 4;
  176.         }
  177.         for (i = 0; i < s.timecnt; ++i)
  178.             s.types[i] = (unsigned char) *p++;
  179.         for (i = 0; i < s.typecnt; ++i) {
  180.             register struct ttinfo *    ttisp;
  181.  
  182.             ttisp = &s.ttis[i];
  183.             ttisp->tt_gmtoff = detzcode(p);
  184.             p += 4;
  185.             ttisp->tt_isdst = (unsigned char) *p++;
  186.             ttisp->tt_abbrind = (unsigned char) *p++;
  187.         }
  188.         for (i = 0; i < s.charcnt; ++i)
  189.             s.chars[i] = *p++;
  190.         s.chars[i] = '\0';    /* ensure '\0' at end */
  191.     }
  192.     /*
  193.     ** Check that all the local time type indices are valid.
  194.     */
  195.     for (i = 0; i < s.timecnt; ++i)
  196.         if (s.types[i] >= s.typecnt)
  197.             return -1;
  198.     /*
  199.     ** Check that all abbreviation indices are valid.
  200.     */
  201.     for (i = 0; i < s.typecnt; ++i)
  202.         if (s.ttis[i].tt_abbrind >= s.charcnt)
  203.             return -1;
  204.     /*
  205.     ** Set tzname elements to initial values.
  206.     */
  207.     tzname[0] = tzname[1] = &s.chars[0];
  208. #ifdef USG_COMPAT
  209.     timezone = -s.ttis[0].tt_gmtoff;
  210.     daylight = 0;
  211. #endif /* USG_COMPAT */
  212.     for (i = 1; i < s.typecnt; ++i) {
  213.         register struct ttinfo *    ttisp;
  214.  
  215.         ttisp = &s.ttis[i];
  216.         if (ttisp->tt_isdst) {
  217.             tzname[1] = &s.chars[ttisp->tt_abbrind];
  218. #ifdef USG_COMPAT
  219.             daylight = 1;
  220. #endif /* USG_COMPAT */ 
  221.         } else {
  222.             tzname[0] = &s.chars[ttisp->tt_abbrind];
  223. #ifdef USG_COMPAT
  224.             timezone = -ttisp->tt_gmtoff;
  225. #endif /* USG_COMPAT */ 
  226.         }
  227.     }
  228.     return 0;
  229. }
  230.  
  231. static
  232. tzsetkernel()
  233. {
  234.     struct timeval    tv;
  235.     struct timezone    tz;
  236.     char    *_tztab();
  237.  
  238.     if (gettimeofday(&tv, &tz))
  239.         return -1;
  240.     s.timecnt = 0;        /* UNIX counts *west* of Greenwich */
  241.     s.ttis[0].tt_gmtoff = tz.tz_minuteswest * -SECS_PER_MIN;
  242.     s.ttis[0].tt_abbrind = 0;
  243.     (void)strcpy(s.chars, _tztab(tz.tz_minuteswest, 0));
  244.     tzname[0] = tzname[1] = s.chars;
  245. #ifdef USG_COMPAT
  246.     timezone = tz.tz_minuteswest * 60;
  247.     daylight = tz.tz_dsttime;
  248. #endif /* USG_COMPAT */
  249.     return 0;
  250. }
  251.  
  252. static
  253. tzsetgmt()
  254. {
  255.     s.timecnt = 0;
  256.     s.ttis[0].tt_gmtoff = 0;
  257.     s.ttis[0].tt_abbrind = 0;
  258.     (void) strcpy(s.chars, "GMT");
  259.     tzname[0] = tzname[1] = s.chars;
  260. #ifdef USG_COMPAT
  261.     timezone = 0;
  262.     daylight = 0;
  263. #endif /* USG_COMPAT */
  264. }
  265.  
  266. void
  267. tzset()
  268. {
  269.     register char *    name;
  270.  
  271.     tz_is_set = TRUE;
  272.     name = getenv("TZ");
  273.     if (!name || *name) {            /* did not request GMT */
  274.         if (name && !tzload(name))    /* requested name worked */
  275.             return;
  276.         if (!tzload((char *)0))        /* default name worked */
  277.             return;
  278.         if (!tzsetkernel())        /* kernel guess worked */
  279.             return;
  280.     }
  281.     tzsetgmt();                /* GMT is default */
  282. }
  283.  
  284. struct tm *
  285. localtime(timep)
  286. time_t *    timep;
  287. {
  288.     register struct ttinfo *    ttisp;
  289.     register struct tm *        tmp;
  290.     register int            i;
  291.     time_t                t;
  292.  
  293.     if (!tz_is_set)
  294.         (void) tzset();
  295.     t = *timep;
  296.     if (s.timecnt == 0 || t < s.ats[0]) {
  297.         i = 0;
  298.         while (s.ttis[i].tt_isdst)
  299.             if (++i >= s.timecnt) {
  300.                 i = 0;
  301.                 break;
  302.             }
  303.     } else {
  304.         for (i = 1; i < s.timecnt; ++i)
  305.             if (t < s.ats[i])
  306.                 break;
  307.         i = s.types[i - 1];
  308.     }
  309.     ttisp = &s.ttis[i];
  310.     /*
  311.     ** To get (wrong) behavior that's compatible with System V Release 2.0
  312.     ** you'd replace the statement below with
  313.     **    tmp = offtime((time_t) (t + ttisp->tt_gmtoff), 0L);
  314.     */
  315.     tmp = offtime(&t, ttisp->tt_gmtoff);
  316.     tmp->tm_isdst = ttisp->tt_isdst;
  317.     tzname[tmp->tm_isdst] = &s.chars[ttisp->tt_abbrind];
  318.     tmp->tm_zone = &s.chars[ttisp->tt_abbrind];
  319.     return tmp;
  320. }
  321.  
  322. struct tm *
  323. gmtime(clock)
  324. time_t *    clock;
  325. {
  326.     register struct tm *    tmp;
  327.  
  328.     tmp = offtime(clock, 0L);
  329.     tzname[0] = "GMT";
  330.     tmp->tm_zone = "GMT";        /* UCT ? */
  331.     return tmp;
  332. }
  333.  
  334. static int    mon_lengths[2][MONS_PER_YEAR] = {
  335.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
  336.     31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  337. };
  338.  
  339. static int    year_lengths[2] = {
  340.     DAYS_PER_NYEAR, DAYS_PER_LYEAR
  341. };
  342.  
  343. struct tm *
  344. offtime(clock, offset)
  345. time_t *    clock;
  346. long        offset;
  347. {
  348.     register struct tm *    tmp;
  349.     register long        days;
  350.     register long        rem;
  351.     register int        y;
  352.     register int        yleap;
  353.     register int *        ip;
  354.     static struct tm    tm;
  355.  
  356.     tmp = &tm;
  357.     days = *clock / SECS_PER_DAY;
  358.     rem = *clock % SECS_PER_DAY;
  359.     rem += offset;
  360.     while (rem < 0) {
  361.         rem += SECS_PER_DAY;
  362.         --days;
  363.     }
  364.     while (rem >= SECS_PER_DAY) {
  365.         rem -= SECS_PER_DAY;
  366.         ++days;
  367.     }
  368.     tmp->tm_hour = (int) (rem / SECS_PER_HOUR);
  369.     rem = rem % SECS_PER_HOUR;
  370.     tmp->tm_min = (int) (rem / SECS_PER_MIN);
  371.     tmp->tm_sec = (int) (rem % SECS_PER_MIN);
  372.     tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYS_PER_WEEK);
  373.     if (tmp->tm_wday < 0)
  374.         tmp->tm_wday += DAYS_PER_WEEK;
  375.     y = EPOCH_YEAR;
  376.     if (days >= 0)
  377.         for ( ; ; ) {
  378.             yleap = isleap(y);
  379.             if (days < (long) year_lengths[yleap])
  380.                 break;
  381.             ++y;
  382.             days = days - (long) year_lengths[yleap];
  383.         }
  384.     else do {
  385.         --y;
  386.         yleap = isleap(y);
  387.         days = days + (long) year_lengths[yleap];
  388.     } while (days < 0);
  389.     tmp->tm_year = y - TM_YEAR_BASE;
  390.     tmp->tm_yday = (int) days;
  391.     ip = mon_lengths[yleap];
  392.     for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
  393.         days = days - (long) ip[tmp->tm_mon];
  394.     tmp->tm_mday = (int) (days + 1);
  395.     tmp->tm_isdst = 0;
  396.     tmp->tm_zone = "";
  397.     tmp->tm_gmtoff = offset;
  398.     return tmp;
  399. }
  400.